package org.example.auth.service.impl;

import org.example.auth.contract.request.AuthorityRequestForPage;
import org.example.auth.contract.request.AuthorityRequestForSave;
import org.example.auth.contract.response.AuthorityResponse;
import org.example.auth.contract.response.AuthorityResponseForRole;
import org.example.auth.convert.AuthorityConvert;
import org.example.auth.enums.AuthExceptionEnum;
import org.example.auth.model.entity.Authority;
import org.example.auth.model.entity.RoleAuthority;
import org.example.auth.repository.AuthorityRepository;
import org.example.auth.service.AuthorityService;
import org.example.auth.service.RoleAuthorityService;
import org.example.misc.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 权限和 角色-权限 业务功能单一，处于末端。且操作低频。
 * 改功能 的 删除操作 均采用物理删除。
 */
@Service
public class AuthorityServiceImpl implements AuthorityService {

    @Autowired
    private AuthorityRepository authorityRepository;
    @Autowired
    private RoleAuthorityService roleAuthorityService;
    @Autowired
    private AuthorityConvert authorityConvert;


    @Override
    @Transactional(rollbackOn = Throwable.class)
    public Authority save(AuthorityRequestForSave request) {
        Optional<Authority> optional = authorityRepository.findByContent(request.getContent());
        if (optional.isPresent()) {
            throw new ServiceException(AuthExceptionEnum.AUTHORITY_EXISTED, request.getContent());
        }
        return authorityRepository.save(authorityConvert.cloneFromRequest(request));
    }

    @Override
    public List<Authority> getAllList() {
        return authorityRepository.findAll();
    }

    @Override
    @Transactional(rollbackOn = Throwable.class)
    public void deleteAuthority(Long id) {
        Authority authority = getAuthority(id, true);
        authorityRepository.delete(authority);
        // 删除角色关联的权限
        roleAuthorityService.deleteRoleAuthorityByAuthority(authority);
    }

    private Authority getAuthority(Long id, Boolean flag) {
        Optional<Authority> authorityOptional = authorityRepository.findById(id);
        if (authorityOptional.isEmpty() && flag) {
            throw new ServiceException(AuthExceptionEnum.AUTHORITY_NOT_EXISTED);
        }
        return authorityOptional.get();
    }

    /**
     * 分页查询
     */
    @Override
    public Page<AuthorityResponse> getPage(AuthorityRequestForPage request, Pageable pageable) {
        Authority authority = authorityConvert.cloneFromRequest(request);
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withIgnoreCase()
                .withIgnoreNullValues()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);
        Example<Authority> example = Example.of(authority, matcher);
        Page<Authority> authorityPage = authorityRepository.findAll(example, pageable);
        return authorityPage.map(authorityConvert::clone);
    }

    private List<Authority> getAuthorityList(List<RoleAuthority> roleAuthorityList) {
        Set<Long> authorityIdList = roleAuthorityList.stream().map(RoleAuthority::getAuthorityId).collect(Collectors.toSet());
        return authorityRepository.findByIdIn(authorityIdList);
    }

    /**
     * 获取某个角色的权限，并按照 绑定未绑定分组
     *
     * @param roleId
     * @return
     */
    @Override
    public AuthorityResponseForRole groupAuthorityByRoleId(Long roleId) {
        List<RoleAuthority> bindAuthorities = roleAuthorityService.findByRoleId(roleId);
        Set<Long> bindAuthorityIds = bindAuthorities.stream().map(RoleAuthority::getAuthorityId).collect(Collectors.toSet());
        List<Authority> allAuthorities = authorityRepository.findAll();
        List<AuthorityResponse> bindAuthorityResponses = new ArrayList<>();
        List<AuthorityResponse> unBindAuthorityResponses = new ArrayList<>();
        for (Authority authority : allAuthorities) {
            if (bindAuthorityIds.contains(authority.getId())) {
                bindAuthorityResponses.add(authorityConvert.clone(authority));
            } else {
                unBindAuthorityResponses.add(authorityConvert.clone(authority));
            }
        }
        AuthorityResponseForRole response = new AuthorityResponseForRole();
        response.setRoleId(roleId);
        response.setBindAuthorities(bindAuthorityResponses);
        response.setUnBindAuthorities(unBindAuthorityResponses);
        return response;
    }


}


